package com.example.demo.service.impl;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.IdUtil;
import com.example.demo.entity.AddcolumnParam;
import com.example.demo.entity.BatchForm;
import com.example.demo.mapper.DateBaseMapper;
import com.example.demo.service.DataBaseService;
import org.apache.commons.lang.StringUtils;
import org.apache.ibatis.session.SqlSession;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @date： 2021/12/24
 * @author: wbx
 */
@Service
public class DataBaseServiceImpl implements DataBaseService {

    @Resource
    private DateBaseMapper dateBaseMapper;
    @Resource
    private SqlSession sqlSession;

    /**
     *  获取数据库中所有的表名称
     */
    @Override
    public List<String> getTables() {
        return dateBaseMapper.getTables();
    }

    /**
     *  获取数据库中所有的表名称 及表注释
     */
    @Override
    public List<Map<String, String>> getTablesAndComment(String schema) {
        return dateBaseMapper.getTablesAndComment(schema);
    }

    /**
     *  获取某张数据表的数据信息
     */
    @Override
    public List<Map<String,String>> getTableDetail(String schema, String tableName) {
        return dateBaseMapper.getTableDetail(schema, tableName);
    }

    /**
     *  动态向数据表中新增一行数据
     * @param addcolumnParam 提交信息
     * @return true 成功 / flase  失败
     */
    @Override
    @Transactional
    public Boolean addColumn(AddcolumnParam addcolumnParam) {
        // 获取数据表的所有信息
        List<Map<String, String>> tableDetail = getTableDetail("sakila", addcolumnParam.getTableName());
        Set<String> columns = tableDetail.stream().map(item -> item.get("字段名称")).collect(Collectors.toSet());
        // 判断新增的列名是否存在
        if(columns.contains(addcolumnParam.getColumnName())) {
            return false;
        }
        StringBuilder sb = new StringBuilder("ALTER TABLE ").append(addcolumnParam.getTableName()).append(" ").append("ADD").append(" ");
        sb.append(addcolumnParam.getColumnName()).append(" ");
        sb.append(addcolumnParam.getType()).append(" ");
        sb.append("DEFAULT ");
        if(StringUtils.isNotBlank(addcolumnParam.getDefaultStr())) {
            sb.append(addcolumnParam.getDefaultStr()).append(" ");
        } else {
            sb.append("''").append(" ");
        }

        sb.append("COMMENT ").append("'");
        sb.append(addcolumnParam.getComment()).append("'");
        // 执行sql语句
        ex(sb.toString());
        return true;
    }

    /**
     *  动态向数据表中新增一行数据
     * @param param 提交信息
     * @return true 成功 / flase  失败
     */
    @Override
    @Transactional
    public Boolean addData(Map<String, String> param) {
        // 插入数据前检查
        String tableName = checkTableInfo(param);
        // 放入生成的Id
        param.put("id", IdUtil.simpleUUID());
        Integer result = dateBaseMapper.addData(param, tableName);
        if(result <= 0) {
            throw new RuntimeException("插入数据错误，请重试！");
        }
        return true;
    }

    /**
     *  修改数据库中的一条数据
     * @param param 提交信息
     * @return true 成功 / flase  失败
     */
    @Override
    @Transactional
    public Boolean modifyData(Map<String, String> param) {
        // 修改前检查数据表
        String tableName = checkTableInfo(param);
        // 移除ID字段
        String id = param.remove("id");
        if(StringUtils.isBlank(id)) {
            throw new RuntimeException("修改的数据ID不能为空！");
        }
        Integer result = dateBaseMapper.modifyData(param, tableName, id);
        if(result <= 0) {
            throw new RuntimeException("修改数据错误，请重试！");
        }
        return true;
    }

    /**
     *  动态向数据表中新增多行数据
     * @param batchForm 提交信息
     * @return true 成功 / flase  失败
     */
    @Override
    @Transactional
    public Boolean saveBatch(BatchForm batchForm) {
        List<Map<String, String>> data = batchForm.getData();
        // 数据信息非空校验
        if(CollectionUtils.isEmpty(data)) {
            throw new RuntimeException("数据信息不能为空！");
        }
        String key = "tableName";
        // 数据信息校验
        data.forEach(item -> {
            item.put(key,batchForm.getTableName());
            // 插入数据
            if(!addData(item)) {
                throw new RuntimeException("新增数据错误，请重试！");
            }
        });
        return true;
    }


    /**
     *  执行完整sql
     * @param sql sql语句
     */
    private void ex(String sql) {
        Connection connections = null;
        try {
            connections = sqlSession.getConfiguration().getEnvironment().getDataSource().getConnection();
            Statement statement = connections.createStatement();
            statement.execute(sql);
            connections.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    /**
     *  数据表及表中数据检查
     * @param param 数据信息
     * @return 数据表名称
     */
    private String checkTableInfo(Map<String, String> param) {
        // 数据信息非空校验
        if(MapUtil.isEmpty(param)) {
            throw new RuntimeException("数据信息不能为空！");
        }
        // 移除表名
        String tableName = param.remove("tableName");
        // 判断当前数据库是否有该数据表
        if(StringUtils.isBlank(tableName) || !(getTables().contains(tableName))) {
            throw new RuntimeException("数据表不存在！");
        }
        // 获取数据表的所有信息
        List<Map<String, String>> tableDetail = getTableDetail("sakila", tableName);
        // 获取数据表所有字段名
        Set<String> columns = tableDetail.stream().map(item -> item.get("字段名称")).collect(Collectors.toSet());
        // 如果传入的字段数量大于数据库表的字段数量
        param.forEach((item, val) -> {
            if(!columns.contains(item)) {
                throw new RuntimeException("数据字段错误，请检查！");
            }
        });
        return tableName;
    }
}
